<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>src/lib/util.coffee</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/3.9.1/build/cssgrids/cssgrids-min.css">
    <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
    <link rel="stylesheet" href="../assets/css/main.css" id="site_styles">
    <link rel="icon" href="../assets/favicon.ico">
    <script src="http://yui.yahooapis.com/combo?3.9.1/build/yui/yui-min.js"></script>
</head>
<body class="yui3-skin-sam">

<div id="doc">
    <div id="hd" class="yui3-g header">
        <div class="yui3-u-3-4">
                <h1><img src="../assets/css/logo.png" title="" width="117" height="52"></h1>
        </div>
        <div class="yui3-u-1-4 version">
            <em>API Docs for: </em>
        </div>
    </div>
    <div id="bd" class="yui3-g">

        <div class="yui3-u-1-4">
            <div id="docs-sidebar" class="sidebar apidocs">
                <div id="api-list">
                    <h2 class="off-left">APIs</h2>
                    <div id="api-tabview" class="tabview">
                        <ul class="tabs">
                            <li><a href="#api-classes">Classes</a></li>
                            <li><a href="#api-modules">Modules</a></li>
                        </ul>
                
                        <div id="api-tabview-filter">
                            <input type="search" id="api-filter" placeholder="Type to filter APIs">
                        </div>
                
                        <div id="api-tabview-panel">
                            <ul id="api-classes" class="apis classes">
                                <li><a href="../classes/BasePlugin.html">BasePlugin</a></li>
                                <li><a href="../classes/Collection.html">Collection</a></li>
                                <li><a href="../classes/Docpad.html">Docpad</a></li>
                                <li><a href="../classes/docpadUtil.html">docpadUtil</a></li>
                                <li><a href="../classes/DocumentModel.html">DocumentModel</a></li>
                                <li><a href="../classes/ElementsCollection.html">ElementsCollection</a></li>
                                <li><a href="../classes/Events.html">Events</a></li>
                                <li><a href="../classes/FileModel.html">FileModel</a></li>
                                <li><a href="../classes/FilesCollection.html">FilesCollection</a></li>
                                <li><a href="../classes/MetaCollection.html">MetaCollection</a></li>
                                <li><a href="../classes/Model.html">Model</a></li>
                                <li><a href="../classes/PluginLoader.html">PluginLoader</a></li>
                                <li><a href="../classes/PluginTester.html">PluginTester</a></li>
                                <li><a href="../classes/QueryCollection.html">QueryCollection</a></li>
                                <li><a href="../classes/ScriptCollection.html">ScriptCollection</a></li>
                                <li><a href="../classes/ServerTester.html">ServerTester</a></li>
                                <li><a href="../classes/StylesCollection.html">StylesCollection</a></li>
                            </ul>
                
                
                            <ul id="api-modules" class="apis modules">
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="yui3-u-3-4">
                <div id="api-options">
                    Show:
                    <label for="api-show-inherited">
                        <input type="checkbox" id="api-show-inherited" checked>
                        Inherited
                    </label>
            
                    <label for="api-show-protected">
                        <input type="checkbox" id="api-show-protected">
                        Protected
                    </label>
            
                    <label for="api-show-private">
                        <input type="checkbox" id="api-show-private">
                        Private
                    </label>
                    <label for="api-show-deprecated">
                        <input type="checkbox" id="api-show-deprecated">
                        Deprecated
                    </label>
            
                </div>
            
            <div class="apidocs">
                <div id="docs-main">
                    <div class="content">
<h1 class="file-heading">File: src/lib/util.coffee</h1>

<div class="file">
    <pre class="code prettyprint linenums">
# =====================================
# Requires

# Standard Library
pathUtil = require(&#x27;path&#x27;)
util = require(&#x27;util&#x27;)

# External
{uniq, compact} = require(&#x27;underscore&#x27;)
extractOptsAndCallback = require(&#x27;extract-opts&#x27;)
{TaskGroup} = require(&#x27;taskgroup&#x27;)


# =====================================
# Export
###*
# The DocPad Util Class.
# Collection of DocPad utility methods
# @class docpadUtil
# @constructor
# @static
###
module.exports = docpadUtil =

	###*
	# Write to stderr
	# @private
	# @method writeStderr
	# @param {String} data
	###
	writeStderr: (data) -&gt;
		try
			process.stderr.write(data)
		catch err
			process.stdout.write(data)

	###*
	# Write an error
	# @private
	# @method writeError
	# @param {Object} err
	###
	writeError: (err) -&gt;
		docpadUtil.writeStderr(err.stack?.toString?() or err.message or err)

	###*
	# Wait. Wrapper for setTimeout
	# @private
	# @method wait
	# @param {Number} time
	# @param {function} fn
	###
	wait: (time, fn) -&gt; setTimeout(fn, time)


	###*
	# Get Default Log Level
	# @private
	# @method getDefaultLogLevel
	# @return {Number} default log level
	###
	getDefaultLogLevel: -&gt;
		if docpadUtil.isTravis() or (&#x27;-d&#x27; in process.argv)
			return 7
		else
			return 5

	###*
	# Are we executing on Travis
	# @private
	# @method isTravis
	# @return {String} The travis node version
	###
	isTravis: -&gt;
		return process.env.TRAVIS_NODE_VERSION?

	###*
	# Is this TTY
	# @private
	# @method isTTY
	# @return {Boolean}
	###
	isTTY: -&gt;
		return process.stdout?.isTTY is true and process.stderr?.isTTY is true


	###*
	# Is Standadlone
	# @private
	# @method isStandalone
	# @return {Object}
	###
	isStandalone: -&gt;
		return /docpad$/.test(process.argv[1] or &#x27;&#x27;)

	###*
	# Is user
	# @private
	# @method isUser
	# @return {Boolean}
	###
	isUser: -&gt;
		return docpadUtil.isStandalone() and docpadUtil.isTTY() and docpadUtil.isTravis() is false

	###*
	# Wrapper for the node.js method util.inspect
	# @method inspect
	# @param {Object} obj
	# @param {Object} opts
	# @return {String}
	###
	inspect: (obj, opts) -&gt;
		# Prepare
		opts ?= {}

		# If the terminal supports colours, and the user hasn&#x27;t set anything, then default to a sensible default
		if docpadUtil.isTTY()
			opts.colors ?= &#x27;--no-colors&#x27; not in process.argv

		# If the terminal doesn&#x27;t support colours, then over-write whatever the user set
		else
			opts.colors = false

		# Inspect and return
		return util.inspect(obj, opts)

	###*
	# Are we using standard encoding?
	# @private
	# @method isStandardEncoding
	# @param {String} encoding
	# @return {Boolean}
	###
	isStandardEncoding: (encoding) -&gt;
		return encoding.toLowerCase() in [&#x27;ascii&#x27;, &#x27;utf8&#x27;, &#x27;utf-8&#x27;]


	###*
	# Get Local DocPad Installation Executable - ie
	# not the global installation
	# @private
	# @method getLocalDocPadExecutable
	# @return {String} the path to the local DocPad executable
	###
	getLocalDocPadExecutable: -&gt;
		return pathUtil.join(process.cwd(), &#x27;node_modules&#x27;, &#x27;docpad&#x27;, &#x27;bin&#x27;, &#x27;docpad&#x27;)

	###*
	# Is Local DocPad Installation
	# @private
	# @method isLocalDocPadExecutable
	# @return {Boolean}
	###
	isLocalDocPadExecutable: -&gt;
		return docpadUtil.getLocalDocPadExecutable() in process.argv

	###*
	# Does the local DocPad Installation Exist?
	# @private
	# @method getLocalDocPadExecutableExistance
	# @return {Boolean}
	###
	getLocalDocPadExecutableExistance: -&gt;
		return require(&#x27;safefs&#x27;).existsSync(docpadUtil.getLocalDocPadExecutable()) is true

	###*
	# Spawn Local DocPad Executable
	# @private
	# @method startLocalDocPadExecutable
	# @param {Function} next
	# @return {Object} don&#x27;t know what
	###
	startLocalDocPadExecutable: (next) -&gt;
		args = process.argv.slice(2)
		command = [&#x27;node&#x27;, docpadUtil.getLocalDocPadExecutable()].concat(args)
		return require(&#x27;safeps&#x27;).spawn command, {stdio:&#x27;inherit&#x27;}, (err) -&gt;
			if err
				if next
					next(err)
				else
					message = &#x27;An error occured within the child DocPad instance: &#x27;+err.message+&#x27;\n&#x27;
					docpadUtil.writeStderr(message)
			else
				next?()


	###*
	# get a filename without the extension
	# @method getBasename
	# @param {String} filename
	# @return {String} base name
	###
	getBasename: (filename) -&gt;
		if filename[0] is &#x27;.&#x27;
			basename = filename.replace(/^(\.[^\.]+)\..*$/, &#x27;$1&#x27;)
		else
			basename = filename.replace(/\..*$/, &#x27;&#x27;)
		return basename


	###*
	# Get the extensions of a filename
	# @method getExtensions
	# @param {String} filename
	# @return {Array} array of string
	###
	getExtensions: (filename) -&gt;
		extensions = filename.split(/\./g).slice(1)
		return extensions


	###*
	# Get the extension from a bunch of extensions
	# @method getExtension
	# @param {Array} extensions
	# @return {String} the extension
	###
	getExtension: (extensions) -&gt;
		unless require(&#x27;typechecker&#x27;).isArray(extensions)
			extensions = docpadUtil.getExtensions(extensions)

		if extensions.length isnt 0
			extension = extensions.slice(-1)[0] or null
		else
			extension = null

		return extension

	###*
	# Get the directory path.
	# Wrapper around the node.js path.dirname method
	# @method getDirPath
	# @param {String} path
	# @return {String}
	###
	getDirPath: (path) -&gt;
		return pathUtil.dirname(path) or &#x27;&#x27;

	###*
	# Get the file name.
	# Wrapper around the node.js path.basename method
	# @method getFilename
	# @param {String} path
	# @return {String}
	###
	getFilename: (path) -&gt;
		return pathUtil.basename(path)

	###*
	# Get the DocPad out file name
	# @method getOutFilename
	# @param {String} basename
	# @param {String} extension
	# @return {String}
	###
	getOutFilename: (basename, extension) -&gt;
		if basename is &#x27;.&#x27;+extension  # prevent: .htaccess.htaccess
			return basename
		else
			return basename+(if extension then &#x27;.&#x27;+extension else &#x27;&#x27;)

	###*
	# Get the URL
	# @method getUrl
	# @param {String} relativePath
	# @return {String}
	###
	getUrl: (relativePath) -&gt;
		return &#x27;/&#x27;+relativePath.replace(/[\\]/g, &#x27;/&#x27;)

	###*
	# Get the post slug from the URL
	# @method getSlug
	# @param {String} relativeBase
	# @return {String} the slug
	###
	getSlug: (relativeBase) -&gt;
		return require(&#x27;bal-util&#x27;).generateSlugSync(relativeBase)

	###*
	# Perform an action
	# next(err,...), ... = any special arguments from the action
	# this should be it&#x27;s own npm module
	# as we also use the concept of actions in a few other packages.
	# Important concept in DocPad.
	# @method action
	# @param {Object} action
	# @param {Object} opts
	# @param {Function} next
	###
	action: (action,opts,next) -&gt;
		# Prepare
		[opts,next] = extractOptsAndCallback(opts,next)
		me = @
		locale = me.getLocale()
		run = opts.run ? true
		runner = opts.runner ? me.getActionRunner()

		# Array?
		if Array.isArray(action)
			actions = action
		else
			actions = action.split(/[,\s]+/g)

		# Clean actions
		actions = uniq compact actions

		# Exit if we have no actions
		if actions.length is 0
			err = new Error(locale.actionEmpty)
			return next(err); me

		# We have multiple actions
		if actions.length &gt; 1
			actionTaskOrGroup = runner.createGroup &#x27;actions bundle: &#x27;+actions.join(&#x27; &#x27;)

			for action in actions
				# Fetch
				actionMethod = me[action].bind(me)

				# Check
				unless actionMethod
					err = new Error(util.format(locale.actionNonexistant, action))
					return next(err); me

				# Task
				task = actionTaskOrGroup.createTask(action, actionMethod, {args: [opts]})
				actionTaskOrGroup.addTask(task)

		# We have single actions
		else
			# Fetch the action
			action = actions[0]

			# Fetch
			actionMethod = me[action].bind(me)

			# Check
			unless actionMethod
				err = new Error(util.format(locale.actionNonexistant, action))
				return next(err); me

			# Task
			actionTaskOrGroup = runner.createTask(action, actionMethod, {args: [opts]})

		# Create our runner task
		runnerTask = runner.createTask &quot;runner task for action: #{action}&quot;, (continueWithRunner) -&gt;
			# Add our listener for our action
			actionTaskOrGroup.done (args...) -&gt;
				# If we have a completion callback, let it handle the error
				if next
					next(args...)
					args[0] = null

				# Continue with our runner
				continueWithRunner(args...)

			# Run our action
			actionTaskOrGroup.run()

		# Add it and run it
		runner.addTask(runnerTask)
		runner.run()  if run is true

		# Chain
		return me

    </pre>
</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="../assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src="../assets/js/yui-prettify.js"></script>
<script src="../assets/../api.js"></script>
<script src="../assets/js/api-filter.js"></script>
<script src="../assets/js/api-list.js"></script>
<script src="../assets/js/api-search.js"></script>
<script src="../assets/js/apidocs.js"></script>
</body>
</html>
